package com.shanxia.codec.cmd;

import com.shanxia.codec.ProtocolDataBase;
import com.shanxia.codec.enums.DecodeEnum;
import lombok.Data;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Objects;

import static com.shanxia.codec.CodeConstant.HUNDRED;
import static com.shanxia.codec.CodeConstant.PERCENT;
import static com.shanxia.codec.Decoder.*;

/**
 * S -> C
 * 后台服务器下发充电桩开启充电控制命令
 * 后台服务器向充电桩开始充电控制命令
 * TODO 文档100字节，demo99字节
 */
@Data
public class Cmd7 extends ProtocolDataBase {

    public static final int MIN_SIZE = 100;

    private int v1;
    private int v2;
    private int pilePort;                    // 充电枪口: 只有一机一桩此参数可为 0，多枪编号从 1 开始
    private int expireType;                  // 充电桩生效类型
    private int stopPwd;                     // 界面充电停止密码
    private int strategy;                    // 充电策略
    private String strategyParam;            // 策略参数
    private String startTime;                // 预约/定时启动时间
    private int overMin;                     // 预约超时时间
    private String sn;                       // 用户卡号/用户识别号
    private int breakNetCharge;              // 断网充电标志
    private double offlinePower;             // 离线可充电电量
    private String serial;                   // 充电流水号
    private int bmsSubVoltage;               // BMS 辅源电压

    public Cmd7(){
        super.setCmd(7);
    }

    public static Cmd7 decodeFromBase(ProtocolDataBase protocolDataBase) {
        Cmd7 cmd = new Cmd7();
        cmd.copyDataFrom(protocolDataBase);
        byte[] dataField = protocolDataBase.getDataField();
        if (dataField.length < MIN_SIZE) {
            cmd.setResult(DecodeEnum.InvalidData);
            return cmd;
        }
        int offset = 0;
        cmd.v1 = getUint16(dataField, offset);
        offset += 2;
        cmd.v2 = getUint16(dataField, offset);
        offset += 2;
        // 1字节充电枪口
        cmd.pilePort = getUint8(dataField[offset++]);
        // 4字节充电生效类型
        cmd.expireType = bytesToIntLittle(dataField, offset);
        offset += 4;
        // 4字节界面充电停止密码
        cmd.stopPwd = bytesToIntLittle(dataField, offset);
        offset += 4;
        // 4字节充电策略
        cmd.strategy = bytesToIntLittle(dataField, offset);
        offset += 4;
        // 4字节充电策略参数
        int param = bytesToIntLittle(dataField, offset);
        if (Objects.equals(cmd.strategy, 2) || Objects.equals(cmd.strategy, 3)) {
            cmd.strategyParam = String.valueOf(new BigDecimal(param).multiply(HUNDRED).doubleValue());
        } else {
            String.valueOf(param);
        }
        offset += 4;
        // 8字节预约/定时启动时间
        cmd.startTime = getStandardTime(dataField, offset);
        offset += 8;
        // 1字节预约超时时间
        cmd.overMin = getUint8(dataField[offset++]);
        // 32字节用户卡号/用户识别号
        cmd.sn = byteToAscii(Arrays.copyOfRange(dataField, offset, offset + 32), true);
        offset += 32;
        // 1字节断网充电标志
        cmd.breakNetCharge = getUint8(dataField[offset++]);
        // 4字节离线可充电电量
        cmd.offlinePower = new BigDecimal(bytesToIntLittle(dataField, offset)).multiply(PERCENT).doubleValue();
        offset += 4;
        // 32字节充电流水号
        cmd.serial = byteToAscii(Arrays.copyOfRange(dataField, offset, offset + 32), true);
        offset += 32;
        // 1字节BMS 辅源电压
        cmd.bmsSubVoltage = getUint8(dataField[offset++]);
        return cmd;
    }

    @Override
    public byte[] getDataField() {
        int offset = 0;
        byte[] buf = new byte[MIN_SIZE];
        getBytesAsUint16(buf, offset, this.v1);
        offset += 2;
        getBytesAsUint16(buf, offset, this.v2);
        offset += 2;
        // 1字节充电枪口
        buf[offset++] = (byte) this.pilePort;
        // 4字节充电生效类型
        intToBytesLittle(buf, offset, this.expireType);
        offset += 4;
        // 4字节界面充电停止密码
        intToBytesLittle(buf, offset, this.stopPwd);
        offset += 4;
        // 4字节充电策略
        intToBytesLittle(buf, offset, this.strategy);
        offset += 4;
        // 4字节充电策略参数
        if (Objects.equals(strategy, 2) || Objects.equals(strategy, 3)) {
            intToBytesLittle(buf, offset, new BigDecimal(String.valueOf(strategyParam)).multiply(HUNDRED).intValue());
        } else {
            intToBytesLittle(buf, offset, Integer.valueOf(strategyParam));
        }
        offset += 4;
        // 8字节预约/定时启动时间
        encodeBasicTime(startTime, buf, offset, true);
        offset += 8;
        // 1字节预约超时时间
        buf[offset++] = (byte) overMin;
        // 32字节用户卡号/用户识别号
        encodeAscii(buf, sn, 32, offset);
        offset += 32;
        // 1字节断网充电标志
        buf[offset++] = (byte) breakNetCharge;
        // 4字节离线可充电电量
        intToBytesLittle(buf, offset, new BigDecimal(String.valueOf(offlinePower)).multiply(HUNDRED).intValue());
        // 32字节充电流水号
        encodeAscii(buf, serial, 32, offset);
        offset += 32;
        // 1字节BMS辅源电压
        buf[offset++] = (byte) bmsSubVoltage;
        return buf;
    }
}
